﻿using Microsoft.EntityFrameworkCore;
using PlatformUW.Contracts;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace PlatformUW.EntityFramework.Repositories
{
    /// <summary>
    /// 默认仓储的通用功能实现，用于所有的领域模型
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TPrimaryKey"></typeparam>

    public class Repositories<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey>
    where TEntity : class
    {
        #region 构造函数 ---------------------------------------------------------------
        /// <summary>
        /// 数据库上下文
        /// </summary>
        protected readonly PlatformDBContext _dbContext;
        /// <summary>
        /// 通过泛型，从数据库上下文中获取领域模型
        /// </summary>
        public virtual DbSet<TEntity> Table => _dbContext.Set<TEntity>();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext"></param>
        public Repositories(PlatformDBContext dbContext)
        {
            _dbContext = dbContext;
        }
        #endregion

        #region 查询 -------------------------------------------------------------------
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns></returns>
        public IQueryable<TEntity> GetAll()
        {
            return Table.AsQueryable();
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns></returns>
        public List<TEntity> GetAllList()
        {
            return GetAll().ToList();
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns></returns>
        public async Task<IEnumerable<TEntity>> GetAllListAsync()
        {
            return await Table.ToListAsync();
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate)
        {
            return GetAll().Where(predicate).ToList();
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await GetAll().Where(predicate).ToListAsync();
        }

        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public TEntity Single(Expression<Func<TEntity, bool>> predicate)
        {
            return GetAll().Single(predicate);
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task<TEntity> SingleAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await GetAll().SingleAsync(predicate);
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>

        public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return GetAll().FirstOrDefault(predicate);
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
        {
            var entity = await GetAll().FirstOrDefaultAsync(predicate);
            return entity;
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public TEntity FirstOrDefaultNoTrack(Expression<Func<TEntity, bool>> predicate)
        {
            return GetAll().AsNoTracking().FirstOrDefault(predicate);
        }
        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task<TEntity> FirstOrDefaultNoTrackAsync(Expression<Func<TEntity, bool>> predicate)
        {
            var entity = await GetAll().AsNoTracking().FirstOrDefaultAsync(predicate);
            return entity;
        }

        #endregion

        #region 插入 -------------------------------------------------------------------
        /// <summary>
        /// 插入
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public TEntity Insert(TEntity entity)
        {
            var newEntity = Table.Add(entity).Entity;
            Save();

            return newEntity;
        }
        /// <summary>
        /// 插入
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<TEntity> InsertAsync(TEntity entity)
        {
            var entityEntry = await Table.AddAsync(entity);

            await SaveAsync();
            return entityEntry.Entity;

        }
        #endregion

        #region 修改 -------------------------------------------------------------------
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public TEntity Update(TEntity entity)
        {
            AttachIfNot(entity);
            _dbContext.Entry(entity).State = EntityState.Modified;
            Save();
            return entity;
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<TEntity> UpdateAsync(TEntity entity)
        {
            AttachIfNot(entity);
            _dbContext.Entry(entity).State = EntityState.Modified;
            await SaveAsync();

            return entity;
        }
        #endregion

        #region 删除 -------------------------------------------------------------------
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="entity"></param>
        public void Delete(TEntity entity)
        {
            AttachIfNot(entity);
            Table.Remove(entity);
            Save();
        }
        /// <summary>
        ///  删除
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task DeleteAsync(TEntity entity)
        {
            AttachIfNot(entity);
            Table.Remove(entity);
            await SaveAsync();
        }
        /// <summary>
        ///  删除
        /// </summary>
        /// <param name="predicate"></param>
        public void Delete(Expression<Func<TEntity, bool>> predicate)
        {
            foreach (var entity in GetAll().Where(predicate).ToList())
            {
                Delete(entity);
            }
        }
        /// <summary>
        ///  删除
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task DeleteAsync(Expression<Func<TEntity, bool>> predicate)
        {
            foreach (var entity in GetAll().Where(predicate).ToList())
            {
                await DeleteAsync(entity);
            }
        }
        #endregion

        #region 统计 -------------------------------------------------------------------
        /// <summary>
        /// 统计总数
        /// </summary>
        /// <returns></returns>
        public int Count()
        {
            return GetAll().Count();
        }
        /// <summary>
        /// 异步统计总数
        /// </summary>
        /// <returns></returns>
        public async Task<int> CountAsync()
        {
            return await GetAll().CountAsync();
        }

        /// <summary>
        /// 异步统计总数
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public int Count(Expression<Func<TEntity, bool>> predicate)
        {
            return GetAll().Where(predicate).Count();
        }

        /// <summary>
        /// 统计总数
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await GetAll().Where(predicate).CountAsync();
        }
        /// <summary>
        /// 异步统计总数
        /// </summary>
        /// <returns></returns>
        public long LongCount()
        {
            return GetAll().LongCount();
        }
        /// <summary>
        /// 异步统计总数
        /// </summary>
        /// <returns></returns>
        public async Task<long> LongCountAsync()
        {
            return await GetAll().LongCountAsync();
        }
        /// <summary>
        /// 异步统计总数
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public long LongCount(Expression<Func<TEntity, bool>> predicate)
        {
            return GetAll().Where(predicate).LongCount();
        }
        /// <summary>
        /// 异步统计总数
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public async Task<long> LongCountAsync(Expression<Func<TEntity, bool>> predicate)
        {
            return await GetAll().Where(predicate).LongCountAsync();
        }
        #endregion

        #region 私有方法 ---------------------------------------------------------------   

        /// <summary>
        /// 检查实体是否处于跟踪状态，如果是则返回，如果没有则添加跟踪状态
        /// </summary>
        /// <param name="entity"></param>
        protected virtual void AttachIfNot(TEntity entity)
        {

            var entry = _dbContext.ChangeTracker.Entries()
                .FirstOrDefault(ent => ent.Entity == entity);

            if (entry != null)
            {
                return;
            }

            Table.Attach(entity);
        }

        /// <summary>
        /// 保存数据
        /// </summary>
        protected void Save()
        {
            //调用数据库上下文保存数据
            _dbContext.SaveChanges();
        }
        /// <summary>
        /// 保存数据
        /// </summary>
        /// <returns></returns>
        protected async Task SaveAsync()
        {
            //调用数据库上下文保存数据的异步方法
            await _dbContext.SaveChangesAsync();
        }

        #endregion
    }
}
